/*
 * Copyright 2015-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dcp.jeedcp.modules.report.service.report;

import com.alibaba.fastjson.JSON;
import com.easytoolsoft.easyreport.engine.data.ColumnType;
import com.easytoolsoft.easyreport.engine.data.ReportDataSource;
import com.easytoolsoft.easyreport.engine.data.ReportMetaDataColumn;
import com.easytoolsoft.easyreport.engine.data.ReportQueryParamItem;
import com.easytoolsoft.easyreport.engine.query.QueryerFactory;
import com.dcp.jeedcp.common.persistence.Page;
import com.dcp.jeedcp.common.service.CrudService;
import com.dcp.jeedcp.common.utils.StringUtils;
import com.dcp.jeedcp.modules.report.dao.report.ReportDao;
import com.dcp.jeedcp.modules.report.domain.QueryParameter;
import com.dcp.jeedcp.modules.report.entity.datasource.Datasource;
import com.dcp.jeedcp.modules.report.entity.report.Report;
import com.dcp.jeedcp.modules.report.entity.report.ReportOptions;
import com.dcp.jeedcp.modules.report.service.datasource.DatasourceService;
import com.dcp.jeedcp.modules.sys.entity.Dict;
import com.dcp.jeedcp.modules.sys.service.DictService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报表设置Service
 * @author henry
 * @version 2017-05-12
 */
@Service
@Transactional(readOnly = true)
public class ReportService extends CrudService<ReportDao, Report> {
	/**
	 * 统计列对应的配置字典表中的Key
	 */
	private static final String STAT_COLUMN = "statColumn";
	/**
	 * 日期列对应的配置字典表中的Key
	 */
	private static final String DATE_COLUMN = "dateColumn";
	/**
	 * 常见维度对应的配置字典表中的Key
	 */
	private static final String DIM_COLUMN = "dimColumn";
	/**
	 * 常见可选列对应的配置字典表中的Key
	 */
	private static final String OPTION_COLUMN = "optionalColumn";

	@Resource
	private DatasourceService dsService;

	@Resource
	private DictService dictService;

	public Report get(String id) {
		return super.get(id);
	}
	
	public List<Report> findList(Report report) {
		return super.findList(report);
	}
	
	public Page<Report> findPage(Page<Report> page, Report report) {
		return super.findPage(page, report);
	}
	
	@Transactional(readOnly = false)
	public void save(Report report) {
		super.save(report);
	}
	
	@Transactional(readOnly = false)
	public void delete(Report report) {
		super.delete(report);
	}

//
	public boolean saveQueryParams(String id, String json) {
		Report report = JSON.parseObject(json, Report.class);
		report.setId(id);
		return this.dao.update(report) > 0;
	}

	

	
	public String getSqlText(String id) {
		Report po = super.get(id);
		return po == null ? "" : po.getSqlText();
	}

	
	public List<ReportMetaDataColumn> getMetaDataColumns(String dsId, String sqlText) {
		List<ReportMetaDataColumn> metaDataColumns = this.executeSqlText(dsId, sqlText);
		Map<String, ReportMetaDataColumn> commonColumnMap = getCommonColumns();
		Map<String, ReportMetaDataColumn> commonOptionColumnMap = getCommonOptionalColumns();

		for (ReportMetaDataColumn column : metaDataColumns) {
			String columnName = column.getName();
			if (commonColumnMap.containsKey(columnName)) {
				ReportMetaDataColumn commonColumn = commonColumnMap.get(columnName);
				column.setType(commonColumn.getType().getValue());
				column.setText(commonColumn.getText());
			}
			if (commonOptionColumnMap.containsKey(columnName)) {
				column.setOptional(true);
				column.setType(commonOptionColumnMap.get(columnName).getType().getValue());
			}
		}
		return metaDataColumns;
	}

	public void explainSqlText(String dsId, String sqlText) {
		this.executeSqlText(dsId, sqlText);
	}

	
	public List<ReportMetaDataColumn> executeSqlText(String dsId, String sqlText) {
		ReportDataSource reportDataSource = getReportDataSource(dsId);
		return QueryerFactory.create(reportDataSource).parseMetaDataColumns(sqlText);
	}

	
	public List<ReportQueryParamItem> executeQueryParamSqlText(String dsId, String sqlText) {
		ReportDataSource reportDataSource = getReportDataSource(dsId);
		return QueryerFactory.create(reportDataSource).parseQueryParamItems(sqlText);
	}

	
	public List<ReportMetaDataColumn> parseMetaColumns(String json) {
		if (StringUtils.isBlank(json)) {
			return new ArrayList<>(0);
		}
		return JSON.parseArray(json, ReportMetaDataColumn.class);
	}

	
	public List<QueryParameter> parseQueryParams(String json) {
		if (StringUtils.isBlank(json)) {
			return new ArrayList<>(0);
		}
		return JSON.parseArray(json, QueryParameter.class);
	}

	
	public ReportOptions parseOptions(String json) {
		if (StringUtils.isBlank(json)) {
			ReportOptions reportOptions = new ReportOptions();
			reportOptions.setDataRange(7);
			reportOptions.setLayout(1);
			reportOptions.setStatColumnLayout(1);
			return reportOptions;
		}
		return JSON.parseObject(json, ReportOptions.class);
	}

	
	public ReportDataSource getReportDataSource(String dsId) {
		Datasource ds = this.dsService.get(dsId);
		Map<String, Object> options = new HashMap<>(3);
		if (StringUtils.isNotEmpty(ds.getOptions())) {
			options = JSON.parseObject(ds.getOptions());
		}
		return new ReportDataSource(
				ds.getId(),
				ds.getDriverClass(),
				ds.getJdbcUrl(), ds.getUser(), ds.getPassword(),
				ds.getQueryerClass(),
				ds.getPoolClass(),
				options);
	}


	private Map<String, ReportMetaDataColumn> getCommonColumns() {
		Dict  dict = new Dict();
		dict.setLabel(STAT_COLUMN);
		List<Dict> confItems = 	dictService.findList(dict);
		Map<String, ReportMetaDataColumn> commonColumnMap =
				this.listToMap(confItems, ColumnType.STATISTICAL, false);

		Dict  query = new Dict();
		query.setParentId(DATE_COLUMN);
		List<Dict> confItemList = 	dictService.findList(query);
		commonColumnMap.putAll(this.listToMap(confItemList, ColumnType.LAYOUT, false));

		Dict  query1 = new Dict();
		query1.setParentId(DIM_COLUMN);
		List<Dict> confItemList2 = 	dictService.findList(query1);
		commonColumnMap.putAll(this.listToMap(confItemList2, ColumnType.DIMENSION, false));
		return commonColumnMap;
	}
	private Map<String, ReportMetaDataColumn> getCommonOptionalColumns() {
		Dict  query = new Dict();
		query.setParentId(OPTION_COLUMN);
		List<Dict> confItemList = 	dictService.findList(query);
		return this.listToMap(confItemList, ColumnType.STATISTICAL, true);
	}

	private Map<String, ReportMetaDataColumn> listToMap(List<Dict> confItems, ColumnType type, boolean isOptional) {
		if (CollectionUtils.isEmpty(confItems)) {
			return new HashMap<>(0);
		}

		Map<String, ReportMetaDataColumn> optionalColumnMap = new HashMap<>(confItems.size());
		for (Dict confItem : confItems) {
			String key = confItem.getLabel().trim().toLowerCase();
			if (!optionalColumnMap.containsKey(key)) {
				ReportMetaDataColumn metaDataColumn =
						new ReportMetaDataColumn(confItem.getLabel(), confItem.getValue(), type);
				metaDataColumn.setOptional(isOptional);
				optionalColumnMap.put(key, metaDataColumn);
			}
		}
		return optionalColumnMap;
	}
}